/**
@author		Jong Min, Lee
@date		  02/08/2014
@brief		Hidden toolbar

copyright(c) Tae Young Soft. All right reserved. 2014
*/
#pragma once

#include <vector>

#include "Taurus_Util/Event.h"
#include "Taurus_Util/Macros.h"
#include "Taurus_Viewer/TBLayoutInfo.h"

class CHiddenToolbar;

/**
@brief		Hidden toolbar item
*/
typedef struct tagHiddenToolbarItem
{
public:
  //text
  CString m_text;

  //item id
  UINT uID;

  //length
  int length;

  //rect
  CRect rect;
}CHiddenToolbarItem;

/**
@brief		hidden toolbar draw base class
*/
class CHiddenToolbarDraw
{
public:
  virtual void drawBK(CHiddenToolbar& toolbar, CDC& dc) {}

  virtual void drawItem(CHiddenToolbar& toolbar, CDC& dc, const CHiddenToolbarItem& item){}
};

/**
@brief		hidden toolbar arrange
*/
class IHiddenToolbarRearrange
{
public:
  virtual CRect getTabMargin(CHiddenToolbar& toolbar, IHiddenToolbarRearrange& base) = 0;
};

class IHiddenToolbarBehavior
{
public:
  virtual const CHiddenToolbarItem* hitTest(CHiddenToolbar& toolbar, IHiddenToolbarBehavior& base, const CPoint& point) = 0;
};

/**
@brief		Hidden toolbar
*/
class CHiddenToolbar : public CWnd
{
	DECLARE_DYNAMIC(CHiddenToolbar)

private:
  DISALLOW_COPY_AND_ASSIGN(CHiddenToolbar);

public:

  typedef struct tagCreateParam
  {
    MonitorResolutionType theResType;

    unsigned int theMonitorIndex;
  }CreateParam;

  /**
  @brief		item id
  */
  enum
  {
    SHOW_TOOLBOX_ITEM,
    SHOW_THUMBNAIL_ITEM
  };

  /**
  @brief		default constructor
  */
	CHiddenToolbar();

  /**
  @brief		destructor
  */
	virtual ~CHiddenToolbar();

  /**
  @brief		set draw manager
  @param		manager pointer to manager
  */
  void setDrawManager(CHiddenToolbarDraw* manager);

  /**
  @brief		access draw manager
  @return		pointer to draw manager
  */
  CHiddenToolbarDraw* getDrawManager() const;

  /**
  @brief		set rearrange manager
  @param		manager pointer to manager
  */
  void setRearrangeManager(IHiddenToolbarRearrange* manager);

  /**
  @brief		access rearrange manager
  @return		pointer to rearrange manager
  */
  IHiddenToolbarRearrange* getRearrangeManager() const;

  /**
  @brief		set behavior manager
  @param		pointer to manager
  */
  void setBehaviorManager(IHiddenToolbarBehavior* manager);

  /**
  @brief		access to behavior manager
  @return		pointer to behavior
  */
  IHiddenToolbarBehavior* getBehaviorManager() const;

  /**
  @brief		set toolbar position
  @param		newPos toolbar position
  @param    redraw flag indicating whether hidden toolbar is to to redrawn
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD setPosition(ToolbarPosition newPos, BOOL redraw);

  /**
  @brief		access to current toolbar position
  @return		current toolbar position
  */
  inline ToolbarPosition getPoistion() const
  {
    return m_position;
  }

/**
  @brief		get the number of items
  @return		the number of items
  */
  inline unsigned getNumItems(void) const
  {
    return m_items.size();
  }

  /**
  @brief		access to item
  @param		index the index number of item to be access
  @return		pointer to item if found, nullptr if not
  */
  const CHiddenToolbarItem* getItem(unsigned index) const;

  /**
  @brief		access to hovered item
  @return		pointer to item if found, nullptr if not
  */
  const CHiddenToolbarItem* getHoverItem() const;

  /**
  @brief		access to pushed item
  @return		pointer to item found, nullptr if not
  */
  const CHiddenToolbarItem* getPushedItem() const;

  /**
  @brief		access item in given point
  @param		point 
  @return		pointer to item if found, null if not
  */
  const CHiddenToolbarItem* hitTest(const CPoint& point);

  /**
  @brief		get index number of a item
  @param		item pointer to item
  @return		>= 0 if found, -1 if not
  */
  int getIndex(const CHiddenToolbarItem* item) const;

  /**
  @brief		check whether an item is exist
  @param		item pointer to item to be checked
  @return		TRUE if exist, FALSE if not
  */
  BOOL isExist(const CHiddenToolbarItem* item) const;

  /**
  @brief		access to monitor index
  */
  unsigned int getMonitorIndex() const
  {
    return m_theMonitorIndex;
  }

  /**
  @brief		event that occurs when an item selected.
            parameter is SHOW_TOOLBOX/SHOW_THUMBNAIL
  */
  TEvent<CHiddenToolbar> onSelectItem;

private:
  class CPaintDC : public CDC
  {
  private:
    DISALLOW_COPY_AND_ASSIGN(CPaintDC);

  public:
    /**
    @brief		constructor
    @param		dcDst pointer to destination device context
    @param    wndDst destination window
    */
    CPaintDC(CDC* dstDC, const CWnd& wndDst);

    /**
    @brief		constructor
    @param		dcDst pointer to destination device context
    @param    rcDst destination rect
    */
    CPaintDC(CDC* dstDC, const CRect& rcDst);

    /**
    @brief		destructor
    */
    ~CPaintDC();

    /**
    @brief		enable or disable double buffering
    @param		enable flag indicating whether enable or disable double buffering
    */
    void enableDoubleBuffering(BOOL enable)
    {
      *getDoubleBufferingFlag() = enable;
    }

    /**
    @brief		check whether double buffering is used or not
    @return		TRUE if double buffering is used, FALSE if not
    */
    BOOL isDoubleBuffering() const
    {
      return *getDoubleBufferingFlag();
    }

  private:
    /**
    @brief		initialize
    @param		dcDst pointer to destination device context
    @return		TRUE if succeeds, FALSE if not
    */
    BOOL init(CDC* dcDst);

    /**
    @brief		access to double buffering flag
    @return		pointer to double buffering flag
    */
    static BOOL* getDoubleBufferingFlag()
    {
      static BOOL doubleBufferingFlag = TRUE;
      return &doubleBufferingFlag;
    }

  private:
    //destination device context
    CDC* m_dcDst;

    //destination rect
    CRect m_rcDst;

    CBitmap m_bmpSrc;

    CBitmap* m_oldBmp;

    BOOL m_success;
  };

private:
  /**
  @brief		create items
  @return		ERROR_SUCCESS upon success, an error code otherwise
  */
  DWORD createItems();

  /**
  @brief		delete all items
  */
  void removeAllItems();

  /**
  @brief		rearrange items
  @param    redraw flag indicating 
  */
  void rearrangne();

  /**
  @brief		calculate length of items
  */
  void calcItemsLength();

  /**
  @brief		calculate rect of items
  */
  void calcItemsRect();

  /**
  @brief		access to item margin
  @return		item margin
  */
  CRect getItemMargin();

  /**
  @brief		assign hover item
  */
  void assignHoverItem(const CPoint& point);

  /**
  @brief		check whether create parameters is legal or not
  @param		params create parameters
  @return		TRUE if legal, FALSE if not
  */
  BOOL validateCreateParams(const CreateParam& params);

private:
  //toolbar position
  ToolbarPosition m_position;

  //monitor resolution type
  MonitorResolutionType m_theResType;

  //monitor index
  unsigned int m_theMonitorIndex;

  //draw manager
  CHiddenToolbarDraw* m_theDrawManager;

  //rearrange manager
  IHiddenToolbarRearrange* m_theRearrangeManager;

  //behavior manager
  IHiddenToolbarBehavior* m_theBehaviorManager;

  //hover item
  const CHiddenToolbarItem* m_hoverItem;

  //pushed item
  const CHiddenToolbarItem* m_pushedItem;

  //items
  std::vector<CHiddenToolbarItem*> m_items;

private:
  class CSerivce : public IHiddenToolbarRearrange, public IHiddenToolbarBehavior, public CHiddenToolbarDraw
  {
  public:
    virtual CRect getTabMargin(CHiddenToolbar& toolbar, IHiddenToolbarRearrange& base);

   virtual const CHiddenToolbarItem* hitTest(CHiddenToolbar& toolbar, IHiddenToolbarBehavior& base, const CPoint& point);

   virtual void drawBK(CHiddenToolbar& toolbar, CDC& dc);

   virtual void drawItem(CHiddenToolbar& toolbar, CDC& dc, const CHiddenToolbarItem& item); 
   
  protected:
    virtual void drawItemBK(CHiddenToolbar& toolbar, CDC& dc, const CHiddenToolbarItem& item);

    virtual void drawItemTitle(CHiddenToolbar& toolbar, CDC& dc, const CHiddenToolbarItem& item);
  };
  CSerivce m_service;

protected:
	DECLARE_MESSAGE_MAP()

public:
  afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
  afx_msg void OnDestroy();
  afx_msg void OnSize(UINT nType, int cx, int cy);
  afx_msg void OnPaint();
  afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
  afx_msg void OnMouseMove(UINT nFlags, CPoint point);
  afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
  LRESULT OnMouseLeave(WPARAM wp, LPARAM lp);
  afx_msg BOOL OnEraseBkgnd(CDC* pDC);
};